﻿using System;
using System.Windows;
using System.Threading;
using System.Text;
using System.Runtime.InteropServices;
using System.Reflection;
using System.IO;
using System.Windows.Navigation;
using System.Windows.Markup;
using System.Globalization;

using PasswordProvider.View.Library;
using PasswordProvider.View;
using PasswordProvider.ViewModel;
using PasswordProvider.ObjectModel;
using PasswordProvider.ViewModel.Service;
using PasswordProvider.ObjectModel.Properties;
using System.ComponentModel;

namespace PasswordProvider
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public sealed partial class App : Application, IDisposable
    {
        private Semaphore _applicationInstanceSemaphore;
        private HelpReader _helpReader;
        private MainWindow _mainWindow;

        public App()
        {
           // The use of a semaphore is the cleanest way to determine if an instance of the app is currently running. 
            bool createdNew;
            _applicationInstanceSemaphore = new Semaphore(1, 2, "donwingatespasswordproviderapplicationsemaphore", out createdNew);
            if (!createdNew)
            {
                // Shut down this instance now.
                this.Shutdown();
            }

            // Ensure the current culture passed into bindings is the OS culture.
            // By default, WPF uses en-US as the culture, regardless of the system settings.            
            FrameworkElement.LanguageProperty.OverrideMetadata(
              typeof(FrameworkElement),
              new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));

            PasswordProvider.ViewModel.Properties.Settings.Default.PropertyChanged += 
                new PropertyChangedEventHandler(ViewModel_Settings_PropertyChanged);
        }

        #region Overrides

        /// <summary>
        /// On Startup, create and open main window, create navigation manager.
        /// </summary>
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            MainWindowViewModel vm = new MainWindowViewModel();
            _mainWindow = new MainWindow();
            
            // Handle main window's Close event and close the help window.
            _mainWindow.Closed +=
                delegate
                {
                    if (_helpReader != null)
                        _helpReader.Close();
                };

            NavigationManager.SetNavigationService(_mainWindow.NavigationService);

            SetMessagingServiceRequestHandlers();

            _mainWindow.DataContext = vm;
            
            string path = Settings.Default.ActiveFilePath;
            if (!String.IsNullOrEmpty(path) && File.Exists(path))
            {
                NavigationManager.GoToEnterPasswordView(path);
            }
            else
            {
                NavigationManager.GoToWelcomePage();
            }

            string skin = ViewModel.Properties.Settings.Default.CurrentSkin;
            if (!string.IsNullOrEmpty(skin))
                LoadSkin(skin);
            
            _mainWindow.Show();

        }

        #endregion

        #region Event Handlers


        void ViewModel_Settings_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "CurrentSkin")
                LoadSkin(ViewModel.Properties.Settings.Default.CurrentSkin);
        }

        #endregion 

        #region Private

        private void SetMessagingServiceRequestHandlers()
        {
            MessagingService.ShowHelpRequest +=
                (sender, e) =>
                {
                    ShowHelp(e.SectionName);
                };

            MessagingService.ShowMessageBoxRequest +=
                (sender, e) =>
                {
                    PasswordProvider.View.MessageBox box = new PasswordProvider.View.MessageBox();
                    e.ViewModel.CloseRequested += delegate { box.Close(); };
                    box.DataContext = e.ViewModel;
                    box.Owner = _mainWindow;
                    box.ShowActivated = true;
                    box.ShowDialog();
                };
        }

        /// <summary>
        /// Show the help window.
        /// </summary>
        private void ShowHelp(string section)
        {
            if (_helpReader == null)
            {
                _helpReader = new HelpReader();

                // Remove the handler when the help reader closes, also set help reader variable to null since it isn't needed.
                _helpReader.Closed += delegate
                {
                    _helpReader = null;
                };

                // Can't attempt to navigate the help reader until it is "really" finished loading.
                EventHandler reallyLoadedHandler = null;
                reallyLoadedHandler = delegate
                {
                    // Go to desired help section.
                    _helpReader.GoTo(section);
                    // Remove this handler from the event now that it has done its job.
                    _helpReader.ReallyLoaded -= reallyLoadedHandler;
                };
                _helpReader.ReallyLoaded += reallyLoadedHandler;

            }
            else
            {
                _helpReader.GoTo(section);
            }
            _helpReader.Show();
            _helpReader.Focus();
        }
        
        private ResourceDictionary _currentSkin;

        private void LoadSkin(string skin)
        {
            if(_currentSkin != null)
                this.Resources.MergedDictionaries.Remove(_currentSkin);

            if (skin == "Default")
                return;
            
            string formatString = @"PasswordProvider.View;component\Dictionary\{0}Skin.xaml";
            string dictionaryUrl = String.Format(CultureInfo.InvariantCulture, formatString, skin);
            Uri url = new Uri(dictionaryUrl, UriKind.Relative);
            _currentSkin = new ResourceDictionary();

            try
            {
                _currentSkin.Source = url;
                if (_currentSkin.Count > 0)
                    this.Resources.MergedDictionaries.Add(_currentSkin);
            }
            catch (IOException)
            {
                // Silently fail...
            }
            

        }

        #endregion

        #region IDisposable Members
        
        public void Dispose()
        {
            if (_applicationInstanceSemaphore != null)
                _applicationInstanceSemaphore.Close();
            if (_mainWindow != null)
                _mainWindow.Dispose();
            
        }

        #endregion
    }
}
